/*!
 * \file CTPOptLoader.cpp
 * \project WonderTrader
 *
 * \author Wesley
 * \date 2020/03/30
 * 
 * \brief CTP期权合约加载器主程序
 * 
 * \details CTP期权合约加载器的主程序实现，主要功能包括：
 *          - 读取配置文件，获取CTP期权连接参数
 *          - 动态加载CTP期权交易API库
 *          - 创建CTP期权交易API实例并注册回调
 *          - 连接CTP期权服务器并查询所有合约信息
 *          - 将查询到的合约和品种信息保存为JSON文件
 *          - 支持自定义品种名称和交易时段映射
 *          - 支持按产品类型过滤（期货、期权、股票等）
 *          - 支持CTP期权API版本3.5.8P4
 */

#include <string>
#include <map>

#include "../API/CTPOpt3.5.8/ThostFtdcTraderApi.h"
#include "TraderSpi.h"

#include "../Share/IniHelper.hpp"
#include "../Share/ModuleHelper.hpp"
#include "../Share/StdUtils.hpp"
#include "../Share/DLLHelper.hpp"
#include <boost/filesystem.hpp>

#ifdef _WIN32
#include "../Share/charconv.hpp"
#endif

// UserApi对象
CThostFtdcTraderApi* pUserApi;

// 配置参数
std::string	FRONT_ADDR;		/*!< 前置地址 */
std::string	BROKER_ID;		/*!< 经纪公司代码 */
std::string	INVESTOR_ID;	/*!< 投资者代码 */
std::string	PASSWORD;		/*!< 用户密码 */
std::string SAVEPATH;		/*!< 保存位置 */
std::string APPID;			/*!< 应用标识 */
std::string AUTHCODE;		/*!< 认证码 */
uint32_t	CLASSMASK;		/*!< 产品类型掩码：1-期货，2-期权，4-股票 */

std::string COMM_FILE;		/*!< 输出的品种文件名 */
std::string CONT_FILE;		/*!< 输出的合约文件名 */

std::string MODULE_NAME;	/*!< 外部模块名 */

typedef std::map<std::string, std::string>	SymbolMap;
SymbolMap	MAP_NAME;		/*!< 品种名称映射表 */
SymbolMap	MAP_SESSION;	/*!< 交易时段映射表 */

typedef CThostFtdcTraderApi* (*CTPCreator)(const char *);
CTPCreator		g_ctpCreator = NULL;	/*!< CTP期权API创建函数指针 */

// 请求编号
int iRequestID = 0;

#ifdef _MSC_VER
#	define EXPORT_FLAG __declspec(dllexport)
#else
#	define EXPORT_FLAG __attribute__((__visibility__("default")))
#endif

#ifdef __cplusplus
extern "C"
{
#endif
	EXPORT_FLAG int run(const char* cfgfile, bool bAsync);
#ifdef __cplusplus
}
#endif

/*!
 * \brief CTP期权合约加载器主函数
 * 
 * \param cfgfile 配置文件路径
 * \param bAsync 是否异步运行，默认false
 * \return 0-成功，其他值-失败
 * 
 * \details 主要执行流程：
 *          1. 读取配置文件，获取CTP期权连接参数和输出设置
 *          2. 加载品种名称和交易时段映射文件
 *          3. 动态加载CTP期权交易API库
 *          4. 创建CTP期权API实例并设置回调
 *          5. 连接CTP期权服务器开始查询合约信息
 *          6. 等待查询完成（同步模式）或立即返回（异步模式）
 */
int run(const char* cfgfile, bool bAsync)
{
	std::string cfg = cfgfile;
	IniHelper ini;
	ini.load(cfg.c_str());

	// 读取CTP期权连接配置
	FRONT_ADDR = ini.readString("ctp", "front", "");
	BROKER_ID	= ini.readString("ctp", "broker", "");
	INVESTOR_ID = ini.readString("ctp", "user", "");
	PASSWORD	= ini.readString("ctp", "pass", "");
	APPID = ini.readString("ctp", "appid", "");
	AUTHCODE = ini.readString("ctp", "authcode", "");

	// 读取输出配置
	SAVEPATH	= ini.readString("config", "path", "");
	CLASSMASK = ini.readUInt("config", "mask", 1 | 2 | 4); // 1-期货，2-期权，4-股票

	COMM_FILE = ini.readString("config", "commfile", "commodities.json");
	CONT_FILE = ini.readString("config", "contfile", "contracts.json");

	// 读取CTP期权API库路径配置
#ifdef _WIN32
	MODULE_NAME = ini.readString("config", "module", "soptthosttraderapi_se.dll");
#else
	MODULE_NAME = ini.readString("config", "module", "soptthosttraderapi_se.so");
#endif
	if(!boost::filesystem::exists(MODULE_NAME.c_str()))
	{
		MODULE_NAME = getBinDir();
#ifdef _WIN32
		MODULE_NAME += "traders/soptthosttraderapi_se.dll";
#else
		MODULE_NAME += "traders/soptthosttraderapi_se.so";
#endif
	}

	// 检查必要参数
	if(FRONT_ADDR.empty() || BROKER_ID.empty() || INVESTOR_ID.empty() || PASSWORD.empty() || SAVEPATH.empty())
	{
		return 0;
	}

	SAVEPATH = StrUtil::standardisePath(SAVEPATH);

	// 加载映射文件（品种名称和交易时段映射）
	std::string map_files = ini.readString("config", "mapfiles", "");
	if (!map_files.empty())
	{
		StringVector ayFiles = StrUtil::split(map_files, ",");
		for (const std::string& fName : ayFiles)
		{
			printf("Reading mapping file %s...\r\n", fName.c_str());
			IniHelper iniMap;
			if (!StdFile::exists(fName.c_str()))
				continue;

			iniMap.load(fName.c_str());
			
			// 读取品种名称映射
			FieldArray ayKeys, ayVals;
			int cout = iniMap.readSecKeyValArray("Name", ayKeys, ayVals);
			for (int i = 0; i < cout; i++)
			{
				MAP_NAME[ayKeys[i]] = ayVals[i];
#ifdef _WIN32
				printf("Commodity name mapping: %s - %s\r\n", ayKeys[i].c_str(), UTF8toChar(ayVals[i]).c_str());
#else
				printf("Commodity name mapping: %s - %s\r\n", ayKeys[i].c_str(), ayVals[i].c_str());
#endif
			}

			// 读取交易时段映射
			ayKeys.clear();
			ayVals.clear();
			cout = iniMap.readSecKeyValArray("Session", ayKeys, ayVals);
			for (int i = 0; i < cout; i++)
			{
				MAP_SESSION[ayKeys[i]] = ayVals[i];
				printf("Trading session mapping: %s - %s\r\n", ayKeys[i].c_str(), ayVals[i].c_str());
			}
		}
	}

	// 初始化UserApi
	DllHandle dllInst = DLLHelper::load_library(MODULE_NAME.c_str());
	if (dllInst == NULL)
		printf("Loading module %s failed\r\n", MODULE_NAME.c_str());
		
	// 获取CTP期权API创建函数（注意期权API的符号名称不同）
#ifdef _WIN32
#	ifdef _WIN64
	g_ctpCreator = (CTPCreator)DLLHelper::get_symbol(dllInst, "?CreateFtdcTraderApi@CThostFtdcTraderApi@ctp_sopt@@SAPEAV12@PEBD@Z");
#	else
	g_ctpCreator = (CTPCreator)DLLHelper::get_symbol(dllInst, "?CreateFtdcTraderApi@CThostFtdcTraderApi@ctp_sopt@@SAPAV12@PBD@Z");
#	endif
#else
	g_ctpCreator = (CTPCreator)DLLHelper::get_symbol(dllInst, "_ZN8ctp_sopt19CThostFtdcTraderApi19CreateFtdcTraderApiEPKc");
#endif
	if (g_ctpCreator == NULL)
		printf("Loading CreateFtdcTraderApi failed\r\n");
		
	// 创建CTP期权API实例
	pUserApi = g_ctpCreator("");			// 创建UserApi	
	CTraderSpi* pUserSpi = new CTraderSpi();
	pUserApi->RegisterSpi((CThostFtdcTraderSpi*)pUserSpi);			// 注册事件类
	pUserApi->SubscribePublicTopic(THOST_TERT_QUICK);					// 注册公有流
	pUserApi->SubscribePrivateTopic(THOST_TERT_QUICK);					// 注册私有流
	pUserApi->RegisterFront((char*)FRONT_ADDR.c_str());				// connect
	pUserApi->Init();

    // 如果不是异步运行，等待API完成
    if(!bAsync)
        pUserApi->Join();

	return 0;
}